package com.bjpowernode.shop.controller;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bjpowernode.shop.base.BaseProduct;
import com.bjpowernode.shop.constants.CommonConstants;
import com.bjpowernode.shop.domain.*;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/prod/prod")
public class ProdController extends BaseProduct {

    // 分页模糊查询
    @GetMapping("/page")
    public ResponseEntity<Page<Prod>> getPage(Page<Prod> page, String prodName, Integer status) {
        return ResponseEntity.ok(prodService.page(page, new LambdaQueryWrapper<Prod>()
                        .like(
                                StringUtils.isNotEmpty(prodName),
                                Prod::getProdName,
                                prodName
                        )
                        .eq(
                                ObjectUtils.isNotEmpty(status),
                                Prod::getStatus,
                                status
                        )
                )
        );
    }

    // 新增产品
    @PostMapping
    @Transactional
    public ResponseEntity<Boolean> saveProd(@RequestBody Prod prod) {
        System.out.println("***prod = " + prod);

        boolean save = prodService.save(
                prod.setShopId(CommonConstants.DEFAULT_SHOP_ID)
                        .setOriPrice(prod.getPrice().multiply(new BigDecimal(10)))
                        .setSoldNum(0)
                        .setDeliveryMode(JSON.toJSONString(prod.getDeliveryModeVo()))
                        .setCreateTime(new Date())
                        .setPutawayTime(new Date())
                        .setVersion(1)
        );

        if (!save)
            throw new RuntimeException("新增产品失败");
        
        /* 产品表对分类表category，多对一 [无需操作表数据]
        产品表对sku表，一对多
        产品表对标签中间表，一对多 */

        // 产品表对sku表，一对多
        List<Sku> skuList = prod.getSkuList();
        skuList.forEach(
                sku -> sku.setProdId(prod.getProdId())
                        .setActualStocks(sku.getStocks())
                        .setRecTime(new Date())
                        .setPartyCode(null)
                        .setModelId(null)
                        .setVersion(1)
                        .setIsDelete(0)
        );
        skuService.saveBatch(skuList);

        // 产品表对标签中间表，一对多
        List<Long> tagIdList = prod.getTagList();
        List<ProdTagReference> referencelist = new ArrayList<>();

        tagIdList.forEach(
                tagId ->
                        referencelist.add(
                                ProdTagReference.builder().shopId(CommonConstants.DEFAULT_SHOP_ID)
                                        .tagId(tagId)
                                        .prodId(prod.getProdId())
                                        .status(1)
                                        .createTime(new Date())
                                        .build()
                        )
        );

        prodTagReferenceService.saveBatch(referencelist);

        return ResponseEntity.ok(save);
    }

    // 修改前展示当前产品信息
    @GetMapping("/info/{id}")
    public ResponseEntity<Prod> info(@PathVariable Long id) {
        // 查询产品信息
        Prod prod = prodService.getById(id);

        // 补充tagList
        List<ProdTagReference> tagReferenceList = prodTagReferenceService.list(
                new LambdaQueryWrapper<ProdTagReference>().eq(ProdTagReference::getProdId, id));
        List<Long> tagIdList = tagReferenceList.stream().map(ProdTagReference::getTagId).collect(Collectors.toList());

        // 补充skuList
        List<Sku> skuList = skuService.list(new LambdaQueryWrapper<Sku>().eq(Sku::getProdId, id));

        // 补充产品信息
        prod.setTagList(tagIdList)
                .setSkuList(skuList);
        return ResponseEntity.ok(prod);
    }

    @PutMapping
    @Transactional
    public ResponseEntity<Boolean> edit(@RequestBody Prod prod) {
        // ====更新TagRef====
        prodTagReferenceService.remove(new LambdaQueryWrapper<ProdTagReference>().eq(
                ObjectUtils.isNotEmpty(prod.getProdId()), ProdTagReference::getProdId, prod.getProdId()
        ));
        List<ProdTagReference> referenceList = prod.getTagList().stream().map(
                tagId -> ProdTagReference.builder()
                        .shopId(CommonConstants.DEFAULT_SHOP_ID)
                        .prodId(prod.getProdId())
                        .tagId(tagId)
                        .status(1)
                        .createTime(new Date())
                        .build()
        ).collect(Collectors.toList());

        prodTagReferenceService.saveBatch(referenceList);

        // ====更新Sku====
        // 设置sku的必要属性
        List<Sku> skuList = prod.getSkuList().stream().map(
                sku -> sku.setProdId(prod.getProdId())
                        .setActualStocks(sku.getStocks())
                        .setRecTime(new Date())
                        .setPartyCode(null)
                        .setModelId(null)
                        .setVersion(1)
                        .setIsDelete(0)
        ).collect(Collectors.toList());


        // 逐条处理sku数据
        for (Sku newSku : skuList) {
            Long newSkuProdId = newSku.getProdId();
            String newSkuSkuName = newSku.getSkuName();
            Map<String, Object> listMap = new HashMap<>();
            listMap.put("prod_id", newSkuProdId);
            listMap.put("sku_name", newSkuSkuName);
            // 当前修改后的sku=newSku，根据newSku的pid和skuName，在数据库中查找原已有数据
            List<Sku> oldSkuListByMap = skuService.listByMap(listMap);

            // 若原已有数据
            if (!CollectionUtils.isEmpty(oldSkuListByMap)) {
                Sku currOldSku = oldSkuListByMap.get(0);
                // 则为newSku设置原已有数据的id，用于更新表数据
                newSku.setSkuId(currOldSku.getSkuId());
                newSku.setUpdateTime(new Date());
                skuService.updateById(newSku);
            } else {
                // 若原无对应数据，则直接新增
                skuService.save(newSku);
            }
        }
        
        /* 
        // 优化前方案：
        // 获取原skuList
        List<Sku> oldSkuList = skuService.list(new LambdaQueryWrapper<Sku>().eq(
                ObjectUtils.isNotEmpty(prod.getProdId()), Sku::getProdId, prod.getProdId()));
        
        // 遍历原skuList，查看是否可直接在该数据上直接更新
        for (Sku oldSku : oldSkuList) {
            // 使用标记查看oldSku是否有对应的sku可在原基础上更新，有则true，无则false
            boolean flag = false;
            
            for (Sku sku : skuList) {
                // 如果找到对应sku
                if (oldSku.getProdId().equals(sku.getProdId()) && oldSku.getSkuName().equals(sku.getSkuName())) {
                    // 则为sku设置oldSku的id，用于更新表数据
                    sku.setSkuId(oldSku.getSkuId());
                    sku.setUpdateTime(new Date());
                    // 更新表数据
                    skuService.updateById(sku);
                    // 将已更新过的sku从skuList中剔除
                    skuList.remove(sku);
                    // 标记当前oldSku为已更新
                    flag = true;
                }
            }

            // 如果遍历完都没找到对应的sku用于更新，则从表中删掉oldSku
            if (flag == false) {
                skuService.removeById(oldSku);
            }
        }
        
        // 将剔除过的skuList全部新增到表中
        skuService.saveBatch(skuList); 
        */

        // ====更新产品信息====
        prod.setUpdateTime(new Date());
        return ResponseEntity.ok(prodService.updateById(prod));
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Boolean> del(@PathVariable Long id) {
        // 删除tag关联中间表中对应的数据
        prodTagReferenceService.remove(new LambdaQueryWrapper<ProdTagReference>().eq(ProdTagReference::getProdId, id));

        // 删除sku表中对应的数据
        skuService.remove(new LambdaQueryWrapper<Sku>().eq(Sku::getProdId, id));

        return ResponseEntity.ok(prodService.removeById(id));
    }

    // ========================Feign远程调用========================
    @GetMapping("/listByPidList")
    public List<Prod> listByPidList(@RequestParam("pidList") List<Long> pidList) {
        return prodService.listByIds(pidList);
    }

    @GetMapping("/listBySkuId")
    public List<Sku> listBySkuId(@RequestParam("skuIdList") List<Long> skuIdList) {
        return skuService.listByIds(skuIdList);
    }

    @PutMapping("/deductDbStock")
    @Transactional
    public Boolean deductDbStock(@RequestBody CountVo countVo) {
        List<ProdCount> prodCountList = countVo.getProdCountList();
        List<SkuCount> skuCountList = countVo.getSkuCountList();

        List<Prod> prodList = new ArrayList<>();

        prodCountList.forEach(
                prodCount -> {
                    Long prodId = prodCount.getProdId();
                    Long count = prodCount.getCount();

                    Prod prod = prodService.getById(prodId);

                    int newStocks = Integer.sum(prod.getTotalStocks(), count.intValue());
                    if (newStocks < 0)
                        throw new RuntimeException("商品库存不足");

                    prod.setTotalStocks(newStocks).setUpdateTime(new Date());

                    prodList.add(prod);
                }
        );

        List<Sku> skuList = new ArrayList<>();

        skuCountList.forEach(
                skuCount -> {
                    Long skuId = skuCount.getSkuId();
                    Long count = skuCount.getCount();

                    Sku sku = skuService.getById(skuId);

                    int newStocks = Integer.sum(sku.getStocks(), count.intValue());
                    if (newStocks < 0)
                        throw new RuntimeException("sku库存不足");
                    int newActualStocks = Integer.sum(sku.getActualStocks(), count.intValue());
                    if (newActualStocks < 0)
                        throw new RuntimeException("sku库存不足");

                    sku.setStocks(newStocks).setActualStocks(newActualStocks).setUpdateTime(new Date());

                    skuList.add(sku);
                }
        );

        boolean prodFlag = prodService.updateBatchById(prodList);
        boolean skuFlag = skuService.updateBatchById(skuList);

        return prodFlag && skuFlag;
    }
}
